home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rules / prs2 / prs2attr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  15.5 KB  |  504 lines

  1.  
  2. /*==================================================================
  3.  *
  4.  * FILE:
  5.  *   prs2attr.c
  6.  *
  7.  * IDENTIFICATION:
  8.  *$Header: /private/postgres/src/rules/prs2/RCS/prs2attr.c,v 1.13 1991/11/18 22:21:22 mer Exp $
  9.  *
  10.  * DESCRIPTION:
  11.  *
  12.  *==================================================================
  13.  */
  14.  
  15. #include "tmp/c.h"
  16. #include "utils/palloc.h"
  17. #include "utils/log.h"
  18. #include "access/ftup.h"    /* ModifyHeapTuple() defined here... */
  19. #include "rules/prs2.h"
  20.  
  21. /*---------------------------------------------------------------------
  22.  *
  23.  * attributeValuesCreate
  24.  *
  25.  * Given a tuple create the corresponding 'AttributeValues' array.
  26.  * Note that in the beginnign all the 'value' entries are copied
  27.  * form the tuple and that 'isCalculated' are all false.
  28.  *
  29.  */
  30.  
  31. AttributeValues
  32. attributeValuesCreate(tuple, buffer, relation)
  33. HeapTuple tuple;
  34. Buffer buffer;
  35. Relation relation;
  36. {
  37.     AttributeNumber i;
  38.     AttributeNumber natts;
  39.     AttributeValues attrValues;
  40.     long size;
  41.     Boolean isNull;
  42.  
  43.     natts = RelationGetNumberOfAttributes(relation);
  44.  
  45.     size = natts * sizeof(AttributeValuesData);
  46.     attrValues = (AttributeValues) palloc(size);
  47.     if (attrValues == NULL) {
  48.     elog(WARN,"attributeValuesCreate: palloc(%ld) failed",size);
  49.     }
  50.  
  51.     for (i=1; i<=natts; i++) {
  52.     attrValues[i-1].value = HeapTupleGetAttributeValue(
  53.                 tuple,
  54.                 buffer,
  55.                 i,
  56.                 RelationGetTupleDescriptor(relation),
  57.                 &isNull);
  58.     attrValues[i-1].isCalculated = (Boolean) 0;
  59.     attrValues[i-1].isChanged = (Boolean) 0;
  60.     attrValues[i-1].isNull = isNull;
  61.     }
  62.  
  63.     return(attrValues);
  64. }
  65.  
  66. /*---------------------------------------------------------------------
  67.  *
  68.  * attributeValuesFree
  69.  *
  70.  * Free a previously allocated 'AttributeValues' array.
  71.  */
  72. void
  73. attributeValuesFree(a, relation)
  74. AttributeValues a;
  75. Relation relation;
  76. {
  77.     int i;
  78.     AttributeNumber natts;
  79.     TupleDescriptor tdesc;
  80.  
  81.     /*
  82.      * free all space (if any) occupied by datums generated
  83.      * by "prs2RunOnePlanAndGetValue()"
  84.      * All these datums are creted via "datumCopy()"
  85.      */
  86.     tdesc = RelationGetTupleDescriptor(relation);
  87.     natts = RelationGetNumberOfAttributes(relation);
  88.     for(i=1; i<=natts; i++) {
  89.     if (a[i-1].isCalculated && a[i-1].isChanged) {
  90.         if (!a[i-1].isNull)
  91.         datumFree(a[i-1].value,
  92.             tdesc->data[i-1]->atttypid,        /* type */
  93.             tdesc->data[i-1]->attbyval,        /* byVal */
  94.             (Size) tdesc->data[i-1]->attlen);    /* type length */
  95.     }
  96.     }
  97.  
  98.     pfree((Pointer)a);
  99. }
  100.  
  101. /*--------------------------------------------------------------------
  102.  *
  103.  * attributeValuesMakeNewTuple
  104.  *
  105.  * Given the old tuple and the values that the new tuple should have
  106.  * create a new tuple.
  107.  *
  108.  * There are a couple of tricky things in here...
  109.  *
  110.  * Some of the attributes of the tuple (not necessarily all of them
  111.  * though..) have been checked for rules, i.e. we have checked if there
  112.  * is any rule that calculates a value for this attribute.
  113.  * All these checked attributes have the field 'isCalculated' (of their
  114.  * corresponding entry in array 'attrValues') equal to true.
  115.  * On top of that, if there was an applicable rule, then the field
  116.  * 'isChanged' is true (todenote that the value of this attribute
  117.  * has changed because of a rule activation, therefore the value
  118.  * stored in 'tuple' is now obsolete).
  119.  * If no applicable rule was found then 'isChanged' is equal to false
  120.  * and the value as stored in 'tuple' is the correct one.
  121.  *
  122.  * Finally all attributes not checked for rule activations (because
  123.  * we don't need to calculate their values for the time being...)
  124.  * have their 'isCalculated' field equal to false.
  125.  *
  126.  * Obviously enough, if at least one attribute has isChanged==true,
  127.  * we must create a new tuple with the correct values in it (we
  128.  * use 'ModifyHeapTuple()' for this purpose).
  129.  * If no attribute has been changed we can use the olt 'tuple'
  130.  * thus avoiding the copy (efficiency!).
  131.  *
  132. #ifdef CHANGE_LOCKS
  133.     ---------------------------------------------------
  134.     XXX Currently we do NOT do that !!!         XXXXXXX
  135.     ---------------------------------------------------
  136.  * However we must also need change the locks of the tuple!
  137.  * Say, if during a retrieve operation, a rule that had a lock of
  138.  * type `LockTypeRetrieveWrite' has been activated and calculated a new
  139.  * value for this attribute, then we must remove this lock, so that if
  140.  * later on (at a higher node in the plan, maybe a join or a topmost
  141.  * result node that is used when the user's operation is an append
  142.  * or delete) we want to find the value of this (laready claculated) 
  143.  * attribute, we do not unnecessarily reactivate the rule.
  144.  * Another case where this happens is when we append a tuple.
  145.  * We have to activate all rules that have `LockTypeAppendWrite' locks,
  146.  * but then we can remove these locks because they are no longer
  147.  * needed (a tuple is only appended once!).
  148.  * The replace case is similar....
  149.  *
  150.  * XXX:
  151.  * Hm.. here comes the tricky question. If no attribute has been
  152.  * changed (i.e. all the 'isChanged' are false) but we must change
  153.  * the locks of the tuple, what shall we do??
  154.  * I think that we have the following options, but I don't know
  155.  * which ones are gonna work and which not:
  156.  *    1) We do not copy the tuple, and we just change its
  157.  *       lock so that it points to the new lock:
  158.  *       tuple->t_lcok.l_lock = newLock;
  159.  *    2) We create a new copy of the tuple with the right locks.
  160.  * I decided to do option # 2.
  161. #else
  162.  * If a new tuple is created, then it will always have an empty
  163.  * lock in it.
  164. #endif CHANGE_LOCKS
  165.  *  
  166.  *
  167.  * This routine returns 0 if no tuple copy has been made and
  168.  * therefore the old 'tuple' can be used, or 1 if there was
  169.  * a tuple copy, in which case the 'newTupleP' point to
  170.  * the new tuple (note: in this case the buffer for this
  171.  * new tuple is the 'InvalidBuffer')
  172.  */
  173.  
  174. int
  175. attributeValuesMakeNewTuple(tuple, buffer, attrValues,
  176.                 locks, lockType, relation, newTupleP)
  177. HeapTuple tuple;
  178. Buffer buffer;
  179. AttributeValues attrValues;
  180. RuleLock locks;
  181. Prs2LockType lockType;
  182. Relation relation;
  183. HeapTuple *newTupleP;
  184. {
  185.     AttributeNumber natts;
  186.     Datum *replaceValue;
  187.     char *replaceNull;
  188.     char *replace;
  189.     long size;
  190.     int i;
  191.     bool tupleHasChanged;
  192.     bool locksHaveToChange;
  193.     HeapTuple t;
  194.     int nlocks;
  195.     RuleLock newLocks;
  196.     Prs2OneLock oneLock;
  197.     AttributeNumber attrNo;
  198.     Prs2LockType thisLockType;
  199.  
  200.     /*
  201.      * find the number of attributes of the tuple
  202.      */
  203.     natts = RelationGetNumberOfAttributes(relation);
  204.  
  205.     /*
  206.      * Find if there was any attribute change and/or we have
  207.      * to change the locks...
  208.      * 
  209.      */
  210.     tupleHasChanged = false;
  211.     for (i=0; i<natts; i++) {
  212.     if (attrValues[i].isCalculated && attrValues[i].isChanged) {
  213.         tupleHasChanged = true;
  214.         break;
  215.     }
  216.     }
  217.  
  218.     if (tupleHasChanged) {
  219.     /*
  220.      * Yes, this tuple has changed because of a rule
  221.      * activation. Create a new tuple with the
  222.      * right attribute values
  223.      *
  224.      * First create some arrays needed by 'ModifyHeapTuple()'
  225.      */
  226.     size = natts * sizeof(Datum);
  227.     replaceValue = (Datum *) palloc(size);
  228.     if (replaceValue == NULL) {
  229.         elog(WARN,"attributeValuesCreate: palloc(%ld) failed",size);
  230.     }
  231.  
  232.     size = natts * sizeof(char);
  233.     replaceNull = (char *) palloc(size);
  234.     if (replaceNull == NULL) {
  235.         elog(WARN,"attributeValuesCreate: palloc(%ld) failed",size);
  236.     }
  237.  
  238.     size = natts * sizeof(Datum);
  239.     replace = (char *) palloc(size);
  240.     if (replace == NULL) {
  241.         elog(WARN,"attributeValuesCreate: palloc(%ld) failed",size);
  242.     }
  243.  
  244.     /*
  245.      * Fill these arrays with the appropriate values
  246.      */
  247.     for (i=0; i<natts; i++) {
  248.         if (attrValues[i].isCalculated && attrValues[i].isChanged) {
  249.         replaceValue[i] = attrValues[i].value;
  250.         replace[i] = 'r';
  251.         if (attrValues[i].isNull) {
  252.             replaceNull[i] = 'n';
  253.         } else {
  254.             replaceNull[i] = ' ';
  255.         }
  256.         } else {
  257.         replace[i] = ' ';
  258.         replaceValue[i] = attrValues[i].value;
  259.         if (attrValues[i].isNull) {
  260.             replaceNull[i] = 'n';
  261.         } else {
  262.             replaceNull[i] = ' ';
  263.         }
  264.         }
  265.     }
  266.  
  267.     /*
  268.      * create the new tuple
  269.      */
  270.     *newTupleP = heap_modifytuple( tuple, buffer,
  271.                 relation, replaceValue,
  272.                 replaceNull, replace);
  273.     /*
  274.      * free the space occupied by the arrays
  275.      */
  276.     pfree((Pointer)replaceValue);
  277.     pfree(replaceNull);
  278.     pfree(replace);
  279.     }
  280.  
  281.  
  282. #ifdef CHANGE_LOCKS
  283.     nlocks = prs2GetNumberOfLocks(locks);
  284.  
  285.     newLocks = prs2MakeLocks();
  286.  
  287.     locksHaveToChange = false;
  288.     for (i=0; i<nlocks; i++) {
  289.     oneLock = prs2GetOneLockFromLocks(locks, i);
  290.     attrNo = prs2OneLockGetAttributeNumber(oneLock);
  291.     thisLockType = prs2OneLockGetLockType(oneLock);
  292.     if (lockType != thisLockType ||
  293.         !attrValues[attrNo-1].isCalculated){
  294.         /*
  295.          * Copy this lock...
  296.          */
  297.         newLocks = prs2AddLock(newLocks,
  298.                 prs2OneLockGetRuleId(oneLock),
  299.                 prs2OneLockGetLockType(oneLock),
  300.                 prs2OneLockGetAttributeNumber(oneLock),
  301.                 prs2OneLockGetPlanNumber(oneLock),
  302.                 prs2OneLockGetPartialIndx(oneLock),
  303.                 prs2OneLockGetNPartial(oneLock));
  304.     } else {
  305.         locksHaveToChange = true;
  306.     }
  307.     }
  308.     /*
  309.      * XXX: For the time being NO locks are stored in tuple,
  310.      * they all come from the RelationRelation.
  311.      * So, WE HAVE to put the locks in the tuple anyway...
  312.      */
  313.     if (prs2GetNumberOfLocks(newLocks) !=0) {
  314.     locksHaveToChange = true;
  315.     }
  316.  
  317.     if (locksHaveToChange && tupleHasChanged) {
  318.     prs2PutLocksInTuple(
  319.                 *newTupleP, InvalidBuffer,
  320.                 relation, newLocks);
  321.     return(1);
  322.     } else if (!locksHaveToChange && tupleHasChanged) {
  323.     /*
  324.      * this is impossible
  325.      */
  326.     elog(WARN,"attributeValuesMakeNewTuple: Internal error");
  327.     } else if (locksHaveToChange && !tupleHasChanged) {
  328.     prs2PutLocksInTuple( tuple, buffer,
  329.                 relation, newLocks);
  330.     *newTupleP = tuple;
  331.     return(1);
  332.     } else if (!locksHaveToChange && !tupleHasChanged) {
  333.     if (newLocks != InvalidRuleLock)
  334.         prs2FreeLocks(newLocks);
  335.     return(0);
  336.     }
  337. #else
  338.     if (tupleHasChanged) {
  339.     /*
  340.      * NOTE: the new tuple, has NO LOCKS IN IT!
  341.      * (well, actually it has an empty lock).
  342.      */
  343.     return(1);
  344.     } else {
  345.     return(0);
  346.     }
  347. #endif CHANGE_LOCKS
  348. }
  349.  
  350. /*--------------------------------------------------------------------
  351.  *
  352.  * attributeValuesCombineNewAndOldTuple
  353.  *
  354.  * Hm.. this is a little bit tricky, so I'll try to do my best:
  355.  * When we want to replace a tuple, the executor has first to retrieve
  356.  * it. So it calls the Access Methods and retrieves what we call the
  357.  * 'raw' tuple, i.e. the tuple as stored in the database.
  358.  * Then it calls the rule manager to activate any 'ON RETRIEVE' rules,
  359.  * and if there are some backward chaining rules that calculate values
  360.  * for some attributes of this tuple, then the rule manager forms a
  361.  * new tuple. This is what we call the 'old' tuple.
  362.  * (NOTE: both the 'old' and 'raw' tuples are stored in the
  363.  * 'qualification_tuple' and 'raw_qualification_tuple' fields of 
  364.  * the 'EState').
  365.  * Finally this 'old' tuple (if it satisfies the qualifications of the
  366.  * replace command) must be replaced. So, the executor forms a new tuple,
  367.  * which is a copy of the 'old' tuple + the updates proposed by the
  368.  * 'replace' command as issued by the user.
  369.  * Then, a final call to the rule manager is made to activate all the
  370.  * 'ON REPLACE' rules. Some of them might be backward chaining rules of
  371.  * the form 'ON REPLACE EMP.salary WHERE .... DO REPLACE CURRENT(desk = ...)'
  372.  * so they might cause even more updated to the tuple and possibly trigger
  373.  * even more rules etc, and to cut a long story short the whole hell can
  374.  * break loose. My completely bug free code handles all these cases
  375.  * in the most perfect way, and what we end up having is:
  376.  * the 'raw' tuple as described above, and a brand 'new' tuple which 
  377.  * incorporates a) all changes made by ON RETRIEVE rules, b) all user
  378.  * updates and c) all changes made by ON REPLACE rules.
  379.  * Well, the tuple that has to be stored in the database (lets call
  380.  * it the 'returned' tuple) must ONLY incorporate (b) and (c).
  381.  * IT MUST NOT INCORPORATE changes made by ON RETRIEVE rules !!!
  382.  * In order to convince all of you that are not as clever as me and
  383.  * can not see the light, here is an example:
  384.  * We have the rule:
  385.  *   ON RETRIEVE TO EMP.salary DO INSTEAD RETRIEVE (salary = 1)
  386.  * and the tuple:
  387.  *   name="spyros", salary = 9999999999999999, status = "prophet"
  388.  * and the user 'replace' command:
  389.  *   replace EMP(status = "god") where EMP.name = "spyros"
  390.  * So the 'raw' tuple is:
  391.  *   name="spyros", salary = 9999999999999999, status = "prophet"
  392.  * the 'old' tuple (after the ON RETRIEVE rule is activated)
  393.  *   name="spyros", salary = 1, status = "prophet"
  394.  * and the 'new' tuple as formed by the executor (after making all changes
  395.  * suggested by the 'replace' command):
  396.  *   name="spyros", salary = 1, status = "god"
  397.  * 
  398.  * Obviously enough, if we store this tuple in the database and
  399.  * then delete the rule, then spyros' salary will be '1' and not
  400.  * what he really deserves (i.e. '9999999999999999').
  401.  * 
  402.  * So, what we have to do, is somehow keep track of what attributes
  403.  * of the 'new' tuple have been changed either by the user ('status')
  404.  * or by ON REPLACE rules (none in our example), and when forming the
  405.  * 'returned' tuple we must use for these attributes the values stored
  406.  * in 'new' tuple, while for all other attributes we have to use
  407.  * the values as stored in 'raw' tuple.
  408.  *
  409.  * In case you haven't suspected it so far, that's exactly what this
  410.  * routine is supposed to do....
  411.  */
  412.  
  413. HeapTuple
  414. attributeValuesCombineNewAndOldTuple(rawAttrValues, newAttrValues,
  415.             relation, attributeArray, numberOfAttributes)
  416. AttributeValues rawAttrValues;        /* values as stored in 'raw' tuple */
  417. AttributeValues newAttrValues;        /* values of the 'new' tuple */
  418. Relation relation;
  419. AttributeNumberPtr attributeArray;    /* attributes changed by the user */
  420. AttributeNumber numberOfAttributes;    /* size of 'attributeArray' */
  421. {
  422.     AttributeNumber natts;
  423.     AttributeNumber i,j;
  424.     Boolean replacedByRule;
  425.     Boolean replacedByUser;
  426.     char *nulls;
  427.     Datum *values;
  428.     HeapTuple resultTuple;
  429.     long int size;
  430.  
  431.     /*
  432.      * find the number of attributes of the tuple
  433.      */
  434.     natts = RelationGetNumberOfAttributes(relation);
  435.  
  436.     /*
  437.      * Now create some arrays needed by 'ModifyHeapTuple()'
  438.      */
  439.     size = natts * sizeof(Datum);
  440.     values = (Datum *) palloc(size);
  441.     if (values == NULL) {
  442.     elog(WARN,"attributeValuesCreate: palloc(%ld) failed",size);
  443.     }
  444.  
  445.     size = natts * sizeof(char);
  446.     nulls = (char *) palloc(size);
  447.     if (nulls == NULL) {
  448.     elog(WARN,"attributeValuesCreate: palloc(%ld) failed",size);
  449.     }
  450.  
  451.     /*
  452.      * Fill these arrays with the right values.
  453.      * For all the attributes of the tuple, check if the
  454.      * attribute has been replaced by the user or by a rule.
  455.      * If yes, then use the value as stored in 'newAttrValues'.
  456.      * Otherwise, use the value as stored in the 'rawAttrValues'.
  457.      */
  458.     for (i=1; i<=natts; i++) {
  459.     replacedByUser = (Boolean) 0;
  460.     for (j=0; j<numberOfAttributes; j++) {
  461.         if (attributeArray[j] == i) {
  462.         replacedByUser = (Boolean) 1;
  463.         break;
  464.         }
  465.     }
  466.     replacedByRule = newAttrValues[i-1].isChanged;
  467.     if (replacedByRule || replacedByUser) {
  468.         values[i-1] = newAttrValues[i-1].value;
  469.         if (newAttrValues[i-1].isNull) {
  470.         nulls[i-1] = 'n';
  471.         } else {
  472.         nulls[i-1] = ' ';
  473.         }
  474.     } else {
  475.         values[i-1] = rawAttrValues[i-1].value;
  476.         if (rawAttrValues[i-1].isNull) {
  477.         nulls[i-1] = 'n';
  478.         } else {
  479.         nulls[i-1] = ' ';
  480.         }
  481.     }
  482.     }
  483.  
  484.     /*
  485.      * create the new tuple
  486.      */
  487.     resultTuple = FormHeapTuple(
  488.             RelationGetNumberOfAttributes(relation),
  489.             RelationGetTupleDescriptor(relation),
  490.             values, nulls);
  491.             
  492.     /*
  493.      * free the space occupied by the arrays
  494.      */
  495.     pfree((Pointer)values);
  496.     pfree(nulls);
  497.  
  498.     /*
  499.      * return the new tuple
  500.      */
  501.     return(resultTuple);
  502. }
  503.  
  504.